package com.autumn.zero.authorization.services.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

import org.springframework.beans.factory.annotation.Autowired;

import com.autumn.common.api.domain.entities.auditing.IGmtDelete;
import com.autumn.common.api.domain.entities.auditing.ISoftDelete;
import com.autumn.domain.repositories.IDefaultEntityRepository;
import com.autumn.domain.services.AbstractDomainService;
import com.autumn.mybatis.criterion.EntityQuery;
import com.autumn.mybatis.criterion.LockModeEnum;
import com.autumn.mybatis.criterion.Query;
import com.autumn.mybatis.criterion.SpecifyUpdate;
import com.autumn.security.constants.UserStatusConstants;
import com.autumn.security.crypto.IAutumnPasswordProvider;
import com.autumn.security.user.DefaultAutumnUser;
import com.autumn.security.user.IAutumnUser;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.StringUtils;
import com.autumn.util.data.DbAuditingUtils;
import com.autumn.validation.MatchesUtils;
import com.autumn.zero.authorization.entitys.AbstractPermission;
import com.autumn.zero.authorization.entitys.modules.ResourcesModule;
import com.autumn.zero.authorization.entitys.modules.ResourcesModulePermission;
import com.autumn.zero.authorization.entitys.roles.AbstractRole;
import com.autumn.zero.authorization.entitys.roles.RoleClaim;
import com.autumn.zero.authorization.entitys.roles.RolePermission;
import com.autumn.zero.authorization.entitys.users.AbstractUser;
import com.autumn.zero.authorization.entitys.users.UserClaim;
import com.autumn.zero.authorization.entitys.users.UserExternalAuthLogin;
import com.autumn.zero.authorization.entitys.users.UserLoginAttempt;
import com.autumn.zero.authorization.entitys.users.UserLoginLog;
import com.autumn.zero.authorization.entitys.users.UserPermission;
import com.autumn.zero.authorization.entitys.users.UserRole;
import com.autumn.zero.authorization.entitys.users.querys.UserClaimQuery;
import com.autumn.zero.authorization.entitys.users.querys.UserPermissionQuery;
import com.autumn.zero.authorization.repositorys.modules.IResourcesModulePermissionRepository;
import com.autumn.zero.authorization.repositorys.modules.IResourcesModuleRepository;
import com.autumn.zero.authorization.repositorys.roles.IRoleClaimRepository;
import com.autumn.zero.authorization.repositorys.roles.IRolePermissionRepository;
import com.autumn.zero.authorization.repositorys.users.IUserClaimRepository;
import com.autumn.zero.authorization.repositorys.users.IUserExternalAuthLoginRepository;
import com.autumn.zero.authorization.repositorys.users.IUserLoginAttemptRepository;
import com.autumn.zero.authorization.repositorys.users.IUserLoginLogRepository;
import com.autumn.zero.authorization.repositorys.users.IUserPermissionRepository;
import com.autumn.zero.authorization.repositorys.users.IUserRoleRepository;
import com.autumn.zero.authorization.repositorys.users.querys.IUserClaimQueryRepository;
import com.autumn.zero.authorization.repositorys.users.querys.IUserPermissionQueryRepository;
import com.autumn.zero.authorization.services.IAuthorizationServiceBase;
import com.autumn.zero.authorization.services.IResourcesService;
import com.autumn.zero.authorization.values.ResourcesModuleTreeValue;

/**
 * 授权抽象服务
 * 
 * @author 杨昌国 2018-11-30 11:09:13
 * @param <TUser>
 *            用户类型
 * @param <TUserRepository>
 *            用户仓储
 * @param <TRole>
 *            角色类型
 * @param <TRoleRepository>
 *            角色仓储
 */
public abstract class AbstractAuthorizationService<TUser extends AbstractUser, TUserRepository extends IDefaultEntityRepository<TUser>, TRole extends AbstractRole, TRoleRepository extends IDefaultEntityRepository<TRole>>
		extends AbstractDomainService implements IAuthorizationServiceBase<TUser, TRole> {

	/**
	 * 获取用户仓储
	 * 
	 * @return
	 */
	protected abstract TUserRepository getUserRepository();

	/**
	 * 获取角色仓储
	 * 
	 * @return
	 */
	protected abstract TRoleRepository getRoleRepository();

	/**
	 * 用户角色仓储
	 */
	@Autowired
	protected IUserRoleRepository userRoleRepository;

	/**
	 * 用户权限仓储
	 */
	@Autowired
	protected IUserPermissionRepository userPermissionRepository;

	/**
	 * 用户声明仓储
	 */
	@Autowired
	protected IUserClaimRepository userClaimRepository;

	/**
	 * 第三方登录仓储
	 */
	@Autowired
	protected IUserExternalAuthLoginRepository userExternalAuthLoginRepository;

	/**
	 * 
	 */
	@Autowired
	protected IUserLoginAttemptRepository userLoginAttemptRepository;

	/**
	 * 用户登录日志
	 */
	@Autowired
	protected IUserLoginLogRepository userLoginLogRepository;

	/**
	 * 角色声明仓储
	 */
	@Autowired
	protected IRoleClaimRepository roleClaimRepository;

	/**
	 * 角色权限仓储
	 */
	@Autowired
	protected IRolePermissionRepository rolePermissionRepository;

	/**
	 * 密码提供者
	 */
	@Autowired
	protected IAutumnPasswordProvider passwordProvider;

	/**
	 * 用户权限查询
	 */
	@Autowired
	protected IUserPermissionQueryRepository userPermissionQueryRepository;

	/**
	 * 用户声明查询
	 */
	@Autowired
	protected IUserClaimQueryRepository userClaimQueryRepository;

	/**
	 * 资源模块仓储
	 */
	@Autowired
	protected IResourcesModuleRepository resourcesModuleRepository;

	/**
	 * 资源模块权限仓储
	 */
	@Autowired
	protected IResourcesModulePermissionRepository resourcesModulePermissionRepository;

	/**
	 * 资源服务
	 */
	@Autowired
	protected IResourcesService resourcesService;

	/**
	 * 用户实体类型
	 */
	private final Class<TUser> userEntityClass;

	/**
	 * 角色实体类型
	 */
	private final Class<TRole> roleEntityClass;

	/**
	 * 实例化 AbstractUserService 类
	 * 
	 * @param userEntityClass
	 *            用户实体类型
	 * @param roleEntityClass
	 *            角角实体类型
	 */
	public AbstractAuthorizationService(Class<TUser> userEntityClass, Class<TRole> roleEntityClass) {
		this.userEntityClass = ExceptionUtils.checkNotNull(userEntityClass, "userEntityClass");
		this.roleEntityClass = ExceptionUtils.checkNotNull(roleEntityClass, "roleEntityClass");
	}

	/**
	 * 获取用户实体类型
	 * 
	 * @return
	 */
	public final Class<TUser> getUserEntityClass() {
		return this.userEntityClass;
	}

	/**
	 * 获取角色实体类型
	 * 
	 * @return
	 */
	public final Class<TRole> getRoleEntityClass() {
		return this.roleEntityClass;
	}

	/**
	 * 检查用户
	 * 
	 * @param user
	 *            用户
	 */
	protected void checkUserEdit(TUser user, boolean checkUserName, boolean checkPhoneNumber,
			boolean checkEmailAddress) {
		if (user.getRoles() == null) {
			user.setRoles(new ArrayList<>());
		}
		EntityQuery<TUser> userQuery = new EntityQuery<>(this.getUserEntityClass());
		if (checkUserName) {
			userQuery.reset();
			userQuery.eq(AbstractUser.FILED_USER_NAME, user.getUserName());
			if (userQuery.countByWhere(this.getUserRepository()) > 0) {
				ExceptionUtils.throwValidationException("用户名称 " + user.getUserName() + " 已存在。");
			}
		}
		if (checkPhoneNumber && !StringUtils.isNullOrBlank(user.getPhoneNumber())) {
			userQuery.reset();
			userQuery.eq(AbstractUser.FILED_PHONE_NUMBER, user.getPhoneNumber().trim());
			if (userQuery.countByWhere(this.getUserRepository()) > 0) {
				ExceptionUtils.throwValidationException("手机号 " + user.getPhoneNumber() + " 已存在或已注册过。");
			}
		}
		if (checkEmailAddress && !StringUtils.isNullOrBlank(user.getEmailAddress())) {
			userQuery.reset();
			userQuery.eq(AbstractUser.FILED_EMAIL_ADDRESS, user.getEmailAddress().trim());
			if (userQuery.countByWhere(this.getUserRepository()) > 0) {
				ExceptionUtils.throwValidationException("邮箱 " + user.getEmailAddress() + " 已存在或已注册过。");
			}
		}
		TRoleRepository roleRepository = this.getRoleRepository();
		int row = 1;
		for (UserRole role : user.getRoles()) {
			Query query = new Query(this.getRoleEntityClass());
			query.eq(AbstractRole.FILED_ID, role.getRoleId());
			if (roleRepository.countByWhere(query.builderSection()) == 0) {
				ExceptionUtils.throwValidationException("第" + row + "行的角色不存在。");
			}
			row++;
		}
	}

	/**
	 * 是否是软删除用户实体
	 * 
	 * @return
	 */
	protected final boolean isSoftDeleteUserEntity() {
		return ISoftDelete.class.isAssignableFrom(this.getUserEntityClass());
	}

	/**
	 * 删除用户详情
	 * 
	 * @param userId
	 *            用户id
	 */
	protected int deleteUserDetails(long userId) {
		int count = 0;
		Query query = new Query(UserRole.class);
		query.eq(UserRole.FILED_USER_ID, userId);
		count += userRoleRepository.deleteByWhere(query.builderSection());

		query = new Query(UserClaim.class);
		query.eq(UserClaim.FILED_USER_ID, userId);
		count += userClaimRepository.deleteByWhere(query.builderSection());

		query = new Query(UserExternalAuthLogin.class);
		query.eq(UserExternalAuthLogin.FILED_USER_ID, userId);
		count += userExternalAuthLoginRepository.deleteByWhere(query.builderSection());

		/*
		 * query = new Query(UserLoginLog.class); query.eq(UserLoginLog.FILED_USER_ID,
		 * userId); count +=
		 * userLoginLogRepository.deleteByWhere(query.builderSection());
		 * 
		 * query = new Query(UserLoginAttempt.class);
		 * query.eq(UserLoginAttempt.FILED_USER_ID, userId); count +=
		 * userLoginAttemptRepository.deleteByWhere(query.builderSection());
		 */

		count += this.deleteUserPermission(userId, null);

		return count;
	}

	/**
	 * 删除用户权取
	 * 
	 * @param userId
	 *            用户id
	 * @param resourcesType
	 *            资源类型
	 * @return
	 */
	private int deleteUserPermission(long userId, Integer resourcesType) {
		int count = 0;
		if (resourcesType == null) {
			EntityQuery<UserPermission> query = new EntityQuery<>(UserPermission.class);
			query.eq(UserPermission.FILED_USER_ID, userId);
			count += query.deleteByWhere(this.userPermissionRepository);
		} else {
			count += this.userPermissionRepository.deleteByUserAndResourcesType(userId, resourcesType);
		}
		return count;
	}

	/**
	 * 查找默认角色集合
	 * 
	 * @return
	 */
	protected List<TRole> findDefaultRoles() {
		Query query = new Query(this.getRoleEntityClass());
		query.eq(AbstractRole.FILED_IS_DEFAULT, "true");
		List<TRole> roles = this.getRoleRepository().selectList(query.builderSection());
		return roles;
	}

	/**
	 * 添加用户的角色
	 * 
	 * @param user
	 * @param roles
	 */
	protected void addUserRoles(TUser user, List<TRole> roles) {
		if (roles != null) {
			for (TRole role : roles) {
				UserRole userRole = new UserRole();
				userRole.setUserId(user.getId());
				userRole.setRoleId(role.getId());
				this.userRoleRepository.insert(userRole);
			}
		}
		for (UserRole role : user.getRoles()) {
			role.setUserId(user.getId());
			if (roles != null) {
				boolean existRole = roles.stream().anyMatch(r -> {
					return r.getId().equals(role.getRoleId());
				});
				if (!existRole) {
					this.userRoleRepository.insert(role);
				}
			} else {
				this.userRoleRepository.insert(role);
			}
		}
	}

	@Override
	public void addUser(TUser user, boolean isAddDefaultRole) {
		ExceptionUtils.checkNotNull(user, "user");
		user.valid();
		this.checkUserEdit(user, true, true, true);
		TUserRepository userRepository = this.getUserRepository();
		user.setStatus(UserStatusConstants.NORMAL);
		user.setGmtCreate(new Date());
		user.setGmtModified(null);
		user.setIsActivateEmail(false);
		user.setIsActivatePhone(false);
		user.forNullToDefault();
		String password = user.getPassword();
		user.setPassword("");
		userRepository.insert(user);
		List<TRole> roles = new ArrayList<>();
		if (isAddDefaultRole) {
			roles = this.findDefaultRoles();
		}
		this.addUserRoles(user, roles);
		this.updatePassword(user, password);
	}

	/**
	 * 更新密码
	 * 
	 * @param userId
	 *            用户id
	 * @param oldPassword
	 *            旧密码
	 * @param newPassword
	 *            新密码
	 */
	@Override
	public void updatePassword(long userId, String oldPassword, String newPassword) {
		ExceptionUtils.checkNotNullOrBlank(oldPassword, "oldPassword");
		ExceptionUtils.checkNotNullOrBlank(newPassword, "newPassword");
		TUserRepository userRepository = this.getUserRepository();
		TUser user = userRepository.get(userId);
		if (user == null) {
			ExceptionUtils.throwValidationException("指定的用户不存在,无法更新密码。");
		}
		IAutumnUser autumnUser = this.createAutumnUser(user);
		if (!passwordProvider.matches(autumnUser, oldPassword)) {
			ExceptionUtils.throwValidationException("旧密码不正确。");
		}
		this.updatePassword(user, newPassword);
	}

	@Override
	public void resetPassword(long userId, String newPassword) {
		ExceptionUtils.checkNotNullOrBlank(newPassword, "newPassword");
		TUserRepository userRepository = this.getUserRepository();
		TUser user = userRepository.get(userId);
		if (user == null) {
			ExceptionUtils.throwValidationException("指定的用户不存在，无法重置密码");
		}
		this.updatePassword(user, newPassword);
	}

	/**
	 * 创建用户
	 * 
	 * @param user
	 *            用户
	 * @return
	 */
	private IAutumnUser createAutumnUser(TUser user) {
		DefaultAutumnUser autumnUser = new DefaultAutumnUser();
		autumnUser.setId(user.getId());
		autumnUser.setUserName(user.getUserName());
		autumnUser.setPassword(user.getPassword());
		autumnUser.setStatus(user.getStatus());
		return autumnUser;
	}

	/**
	 * 更新密码
	 * 
	 * @param user
	 *            用户
	 * @param newPassword
	 *            新密码
	 */

	private void updatePassword(TUser user, String newPassword) {
		IAutumnUser autumnUser = this.createAutumnUser(user);
		String password = passwordProvider.encode(autumnUser, newPassword);
		if (password == null) {
			password = "";
		}
		user.setPassword(password);
		SpecifyUpdate su = new SpecifyUpdate(this.getUserEntityClass());
		su.set(AbstractUser.FILED_PASSWORD, password).eq(AbstractUser.FILED_ID, user.getId());
		TUserRepository userRepository = this.getUserRepository();
		userRepository.updateBySpecify(su.builderSection());
	}

	@Override
	public void updateUser(TUser user) {
		ExceptionUtils.checkNotNull(user, "user");
		// user.setStatus(UserStatusConstants.NORMAL);
		user.valid();
		user.forNullToDefault();
		TUserRepository userRepository = this.getUserRepository();
		TUser entity = userRepository.get(user.getId());
		if (entity == null) {
			ExceptionUtils.throwValidationException("无法更新不存在的用户。");
		}
		if (entity.getIsSysUser()) {
			ExceptionUtils.throwValidationException("无法更新系统用户。");
		}
		boolean checkUserName, checkPhoneNumber, checkEmailAddress;
		checkUserName = !entity.getUserName().equalsIgnoreCase(user.getUserName().trim());
		if (StringUtils.isNullOrBlank(user.getPhoneNumber())) {
			checkPhoneNumber = false;
		} else {
			checkPhoneNumber = !user.getPhoneNumber().trim().equalsIgnoreCase(entity.getPhoneNumber());
		}
		if (StringUtils.isNullOrBlank(user.getEmailAddress())) {
			checkEmailAddress = false;
		} else {
			checkEmailAddress = !user.getEmailAddress().trim().equalsIgnoreCase(entity.getEmailAddress());
		}
		this.checkUserEdit(user, checkUserName, checkPhoneNumber, checkEmailAddress);
		user.setGmtCreate(entity.getGmtCreate());
		DbAuditingUtils.updateSetProperty(user);
		user.setPassword(entity.getPassword());
		user.setIsActivateEmail(entity.getIsActivateEmail());
		user.setIsActivatePhone(entity.getIsActivatePhone());
		user.setIsSysUser(entity.getIsSysUser());
		user.setStatus(entity.getStatus());
		Query query = new Query(UserRole.class);
		query.eq(UserRole.FILED_USER_ID, entity.getId());
		userRoleRepository.deleteByWhere(query.builderSection());
		userRepository.update(user);
		this.addUserRoles(user, null);
	}

	/**
	 * 删除用户
	 * 
	 * @param userId
	 */
	@Override
	public void deleteUserById(long userId) {
		TUserRepository userRepository = this.getUserRepository();
		TUser entity = userRepository.get(userId);
		if (entity == null) {
			return;
		}
		if (entity.getIsSysUser()) {
			ExceptionUtils.throwValidationException("不能删除系统用户");
		}
		if (this.isSoftDeleteUserEntity()) {
			SpecifyUpdate su = new SpecifyUpdate(this.getUserEntityClass());
			su.set(ISoftDelete.FILED_IS_DELETE, true);
			if (IGmtDelete.class.isAssignableFrom(this.getUserEntityClass())) {
				su.set(IGmtDelete.FILED_GMT_DELETE, new Date());
			}
			su.eq(AbstractUser.FILED_ID, userId);
			this.getUserRepository().updateBySpecify(su.builderSection());
		} else {
			this.deleteUserDetails(userId);
			this.getUserRepository().deleteByPrimaryKey(userId);
		}
	}

	/**
	 * 查询用户角色集合
	 * 
	 * @param userId
	 * @return
	 */
	private List<UserRole> queryUserRoles(long userId) {
		Query query = new Query(UserRole.class);
		query.eq(UserRole.FILED_USER_ID, userId).orderBy(UserRole.FILED_ID);
		List<UserRole> roles = this.userRoleRepository.selectList(query.builderSection());
		return roles;
	}

	@Override
	public TUser getUser(long userId, boolean isQuerychild) {
		TUser entity = this.getUserRepository().get(userId);
		if (entity != null && isQuerychild) {
			entity.setRoles(this.queryUserRoles(entity.getId()));
		}
		return entity;
	}

	/**
	 * 检查角色
	 * 
	 * @param role
	 */
	protected void checkRoleEdit(TRole role, boolean checkName) {
		if (role.getUsers() == null) {
			role.setUsers(new ArrayList<>());
		}
		EntityQuery<TRole> userQuery = new EntityQuery<>(this.getRoleEntityClass());
		if (checkName) {
			userQuery.reset();
			userQuery.eq(AbstractRole.FILED_NAME, role.getName());
			if (userQuery.countByWhere(this.getRoleRepository()) > 0) {
				ExceptionUtils.throwValidationException("角色名称 " + role.getName() + " 已存在。");
			}
		}
		TUserRepository userRepository = this.getUserRepository();
		int row = 1;
		for (UserRole user : role.getUsers()) {
			Query query = new Query(this.getUserEntityClass());
			query.eq(AbstractUser.FILED_ID, user.getUserId());
			if (userRepository.countByWhere(query.builderSection()) == 0) {
				ExceptionUtils.throwValidationException("第" + row + "行的用户不存在。");
			}
			row++;
		}
	}

	/**
	 * 是否是软删除角色实体
	 * 
	 * @return
	 */
	protected final boolean isSoftDeleteRoleEntity() {
		return ISoftDelete.class.isAssignableFrom(this.getRoleEntityClass());
	}

	/**
	 * 添加角色的用户
	 * 
	 * @param role
	 */
	protected void addRoleUsers(TRole role) {
		for (UserRole user : role.getUsers()) {
			user.setRoleId(role.getId());
			this.userRoleRepository.insert(user);
		}
	}

	@Override
	public void addRole(TRole role) {
		ExceptionUtils.checkNotNull(role, "role");
		role.valid();
		role.forNullToDefault();
		this.checkRoleEdit(role, true);
		TRoleRepository roleRepository = this.getRoleRepository();
		role.setGmtCreate(new Date());
		role.setGmtModified(null);
		roleRepository.insert(role);
		this.addRoleUsers(role);
	}

	/**
	 * 删除角色详情
	 * 
	 * @param roleId
	 *            角色id
	 */
	protected int deleteRoleDetails(long roleId) {
		int count = 0;
		Query query = new Query(UserRole.class);
		query.eq(UserRole.FILED_ROLE_ID, roleId);
		count += this.userRoleRepository.deleteByWhere(query.builderSection());

		query = new Query(RoleClaim.class);
		query.eq(RoleClaim.FILED_ROLE_ID, roleId);
		count += this.roleClaimRepository.deleteByWhere(query.builderSection());

		count += this.deleteRolePermission(roleId, null);
		return count;
	}

	/**
	 * 删除角色权限
	 * 
	 * @param roleId
	 *            角色id
	 * @param resourcesType
	 *            资源类型
	 * @return
	 */
	private int deleteRolePermission(long roleId, Integer resourcesType) {
		int count = 0;
		if (resourcesType == null) {
			EntityQuery<RolePermission> query = new EntityQuery<>(RolePermission.class);
			query.eq(RolePermission.FILED_ROLE_ID, roleId);
			count += query.deleteByWhere(this.rolePermissionRepository);
		} else {
			this.rolePermissionRepository.deleteByRoleAndResourcesType(roleId, resourcesType);
		}
		return count;
	}

	@Override
	public void updateRole(TRole role) {
		ExceptionUtils.checkNotNull(role, "role");
		role.valid();
		role.forNullToDefault();
		TRoleRepository roleRepository = this.getRoleRepository();
		TRole entity = roleRepository.get(role.getId());
		if (entity == null) {
			ExceptionUtils.throwValidationException("无法更新不存在的角色。");
		}
		if (entity.getIsSysRole()) {
			ExceptionUtils.throwValidationException("无法更新系统角色。");
		}
		this.checkRoleEdit(role, !entity.getName().equalsIgnoreCase(role.getName().trim()));
		role.setGmtCreate(entity.getGmtCreate());
		DbAuditingUtils.updateSetProperty(role);
		role.setIsSysRole(entity.getIsSysRole());
		roleRepository.update(role);
		Query query = new Query(UserRole.class);
		query.eq(UserRole.FILED_ROLE_ID, entity.getId());
		userRoleRepository.deleteByWhere(query.builderSection());
		this.addRoleUsers(role);
	}

	@Override
	public void deleteRoleById(long roleId) {
		TRoleRepository roleRepository = this.getRoleRepository();
		TRole entity = roleRepository.get(roleId);
		if (entity == null) {
			return;
		}
		if (entity.getIsSysRole()) {
			ExceptionUtils.throwValidationException("不能删除系统角色。");
		}
		if (this.isSoftDeleteRoleEntity()) {
			SpecifyUpdate su = new SpecifyUpdate(this.getUserEntityClass());
			su.set(IGmtDelete.FILED_IS_DELETE, true);
			if (IGmtDelete.class.isAssignableFrom(this.getUserEntityClass())) {
				su.set(IGmtDelete.FILED_GMT_DELETE, new Date());
			}
			su.eq(AbstractRole.FILED_ID, roleId);
			this.getUserRepository().updateBySpecify(su.builderSection());
		} else {
			this.deleteRoleDetails(roleId);
			this.getRoleRepository().deleteByPrimaryKey(roleId);
		}
	}

	@Override
	public TRole getRole(long roleId, boolean isQuerychild) {
		TRole entity = this.getRoleRepository().get(roleId);
		if (entity != null && isQuerychild) {
			Query query = new Query(UserRole.class);
			query.eq("roleId", entity.getId());
			List<UserRole> roles = this.userRoleRepository.selectList(query.builderSection());
			entity.setUsers(roles);
		}
		return entity;
	}

	/**
	 * 检查权限
	 * 
	 * @param resourcesType
	 *            资源类型
	 * @param permissions
	 *            权限集合
	 */
	private <E extends AbstractPermission> void checkPermission(int resourcesType, List<E> permissions) {
		Set<String> resourcesSet = new HashSet<>();
		Set<String> keySet = new HashSet<>();
		EntityQuery<ResourcesModulePermission> query = new EntityQuery<>(ResourcesModulePermission.class);
		for (E permission : permissions) {
			permission.forNullToDefault();
			permission.valid();
			String resKey = permission.getResourcesId().toLowerCase().trim();
			if (resourcesSet.add(resKey)) {
				ResourcesModule module = resourcesModuleRepository.get(resKey);
				if (module == null) {
					ExceptionUtils.throwValidationException("指定的资源id[" + resKey + "]不存在或无效。");
				}
				if (!module.getResourcesType().equals(resourcesType)) {
					ExceptionUtils.throwValidationException("指定的资源[" + module.getCustomName() + "]对应的资源类型不匹配。");
				}
			}
			if (StringUtils.isNullOrBlank(permission.getName())) {
				if (!keySet.add(permission.getResourcesId().toLowerCase())) {
					ExceptionUtils.throwValidationException("指定的资源id[" + resKey + "]重复授权。");
				}
			} else {
				String name = permission.getName().trim();
				String key = String.format("%s:%s", resKey, name.toLowerCase());
				if (keySet.add(key)) {
					query.reset();
					query.eq(ResourcesModulePermission.FILED_RESOURCES_ID, resKey)
							.eq(ResourcesModulePermission.FILED_NAME, name);
					if (query.countByWhere(this.resourcesModulePermissionRepository) == 0) {
						ExceptionUtils.throwValidationException("指定的资源id[" + resKey + "]与对应的权限[" + name + "]未定义。");
					}

				} else {
					ExceptionUtils.throwValidationException("指定的资源id[" + resKey + "]与对应的权限[" + name + "]重复授权。");
				}
			}
		}
	}

	@Override
	public TUser authorizeByUser(long userId, int resourcesType, List<UserPermission> permissions) {
		if (permissions == null) {
			permissions = new ArrayList<>();
		}
		TUser entity = this.getUser(userId, false);
		if (entity == null) {
			ExceptionUtils.throwValidationException("指定的用户不存在，无法授权。");
		}
		this.checkPermission(resourcesType, permissions);
		this.deleteUserPermission(userId, resourcesType);
		for (UserPermission permission : permissions) {
			permission.setUserId(userId);
			this.userPermissionRepository.insert(permission);
		}
		return entity;
	}

	@Override
	public TRole authorizeByRole(long roleId, int resourcesType, List<RolePermission> permissions) {
		if (permissions == null) {
			permissions = new ArrayList<>();
		}
		TRole entity = this.getRole(roleId, false);
		if (entity == null) {
			ExceptionUtils.throwValidationException("指定的用户不存在，无法授权。");
		}
		this.checkPermission(resourcesType, permissions);
		this.deleteRolePermission(roleId, resourcesType);
		for (RolePermission permission : permissions) {
			permission.setRoleId(roleId);
			this.rolePermissionRepository.insert(permission);
		}
		return entity;
	}

	/**
	 * 授用户或角色所有权限
	 * 
	 * @param resourcesType
	 *            资源类型
	 * @param repository
	 *            仓储
	 * @param permissionClass
	 *            权限类型
	 * @param supplier
	 *            返回处理
	 */
	private <TPermissionEntity extends AbstractPermission, TPermissionRepository extends IDefaultEntityRepository<TPermissionEntity>> void authorizeAllPermission(
			int resourcesType, TPermissionRepository repository, Class<TPermissionEntity> permissionClass,
			Supplier<TPermissionEntity> supplier) {
		EntityQuery<ResourcesModule> resourcesModuleQuery = new EntityQuery<>(ResourcesModule.class);
		resourcesModuleQuery.eq(ResourcesModule.FILED_RESOURCES_TYPE, resourcesType)
				.eq(ResourcesModule.FILED_IS_AUTHORIZE, true).orderBy(ResourcesModule.FILED_PARENT_ID)
				.orderBy(ResourcesModule.FILED_SORT_ID).orderBy(ResourcesModule.FILED_ID);
		List<ResourcesModule> resourcesModules = resourcesModuleQuery.selectByList(this.resourcesModuleRepository);
		Map<String, List<ResourcesModulePermission>> resPermissionMap = this.queryByResourcesTypeMap(resourcesType);
		for (ResourcesModule resourcesModule : resourcesModules) {
			TPermissionEntity permission = supplier.get();
			permission.setIsGranted(true);
			permission.setResourcesId(resourcesModule.getId());
			permission.setName("");
			repository.insert(permission);
			List<ResourcesModulePermission> items = resPermissionMap.get(resourcesModule.getId().toLowerCase());
			if (items != null) {
				for (ResourcesModulePermission item : items) {
					permission = supplier.get();
					permission.setIsGranted(true);
					permission.setResourcesId(resourcesModule.getId());
					permission.setName(item.getName());
					repository.insert(permission);
				}
			}
		}
	}

	/**
	 * 获取资源权限 Map
	 * 
	 * @param resourcesType
	 * @return
	 */
	private Map<String, List<ResourcesModulePermission>> queryByResourcesTypeMap(int resourcesType) {
		Map<String, List<ResourcesModulePermission>> resPermissionMap = new HashMap<>();
		List<ResourcesModulePermission> resPermissionList = this.resourcesModulePermissionRepository
				.queryByResourcesTypes(resourcesType);
		for (ResourcesModulePermission resourcesModulePermission : resPermissionList) {
			String key = resourcesModulePermission.getResourcesId().toLowerCase();
			List<ResourcesModulePermission> items = resPermissionMap.get(key);
			if (items == null) {
				items = new ArrayList<>();
				resPermissionMap.put(key, items);
			}
			items.add(resourcesModulePermission);
		}
		return resPermissionMap;
	}

	@Override
	public void authorizeByUserAllPermission(long userId, int resourcesType) {
		TUser user = this.getUser(userId, false);
		if (user == null) {
			ExceptionUtils.throwValidationException("指定的用户不存在。");
		}
		this.userPermissionRepository.deleteByUserAndResourcesType(userId, resourcesType);
		this.authorizeAllPermission(resourcesType, this.userPermissionRepository, UserPermission.class, () -> {
			UserPermission permission = new UserPermission();
			permission.setUserId(userId);
			return permission;
		});
		DbAuditingUtils.updateSetProperty(user);
		this.getUserRepository().update(user);
	}

	@Override
	public void authorizeByRoleAllPermission(long roleId, int resourcesType) {
		TRole role = this.getRole(roleId, false);
		if (role == null) {
			ExceptionUtils.throwValidationException("指定的用户不存在。");
		}
		this.rolePermissionRepository.deleteByRoleAndResourcesType(roleId, resourcesType);
		this.authorizeAllPermission(resourcesType, this.rolePermissionRepository, RolePermission.class, () -> {
			RolePermission permission = new RolePermission();
			permission.setRoleId(roleId);
			return permission;
		});
		DbAuditingUtils.updateSetProperty(role);
		this.getRoleRepository().update(role);
	}

	@Override
	public List<UserPermission> queryUserPermissions(long userId) {
		EntityQuery<UserPermission> query = new EntityQuery<>(UserPermission.class);
		query.eq(UserPermission.FILED_USER_ID, userId).orderBy(UserPermission.FILED_ID);
		return query.selectByList(this.userPermissionRepository);
	}

	@Override
	public List<UserPermissionQuery> queryUserAllPermissions(long userId) {
		EntityQuery<UserPermissionQuery> query = new EntityQuery<>(UserPermissionQuery.class);
		query.eq(UserPermissionQuery.FILED_USER_ID, userId).orderByDescending(UserPermissionQuery.FILED_IS_GRANTED);
		List<UserPermissionQuery> items = query.selectByList(this.userPermissionQueryRepository);
		List<UserPermissionQuery> results = new ArrayList<>();
		items.forEach(item -> {
			boolean exist = results.stream().anyMatch(c -> {
				return c.getResourcesId().equalsIgnoreCase(item.getResourcesId())
						&& c.getName().equalsIgnoreCase(item.getName());

			});
			if (!exist) {
				results.add(item);
			}
		});
		return results;
	}

	/**
	 * 查询用户的菜单模块
	 * 
	 * @param resourcesType
	 *            资源类型
	 * @param userId
	 *            用户id
	 * @return
	 */
	@Override
	public List<ResourcesModuleTreeValue> queryUserByMenuTree(int resourcesType, long userId) {
		List<UserPermissionQuery> permissions = this.queryUserAllPermissions(userId);
		List<ResourcesModuleTreeValue> moduleTree = resourcesService.queryByMenuTree(resourcesType);
		return resourcesService.filterModuleTree(moduleTree, permissions);
	}

	@Override
	public List<RolePermission> queryRolePermissions(long roleId) {
		EntityQuery<RolePermission> query = new EntityQuery<>(RolePermission.class);
		query.eq(RolePermission.FILED_ROLE_ID, roleId).orderBy(RolePermission.FILED_ID);
		return query.selectByList(this.rolePermissionRepository);
	}

	@Override
	public List<UserClaim> queryUserClaims(long userId) {
		EntityQuery<UserClaim> query = new EntityQuery<>(UserClaim.class);
		query.eq(UserClaim.FILED_USER_ID, userId).orderBy(UserClaim.FILED_ID);
		return query.selectByList(this.userClaimRepository);
	}

	@Override
	public List<UserClaimQuery> queryUserAllClaims(long userId) {
		EntityQuery<UserClaimQuery> query = new EntityQuery<>(UserClaimQuery.class);
		query.eq(UserClaimQuery.FILED_USER_ID, userId);
		List<UserClaimQuery> items = query.selectByList(this.userClaimQueryRepository);
		List<UserClaimQuery> results = new ArrayList<>();
		items.forEach(item -> {
			boolean exist = results.stream().anyMatch(c -> {
				return c.getClaimType().equalsIgnoreCase(item.getClaimType())
						&& c.getClaimValue().equalsIgnoreCase(item.getClaimValue());

			});
			if (!exist) {
				results.add(item);
			}
		});
		return results;
	}

	@Override
	public List<RoleClaim> queryRoleClaims(long roleId) {
		EntityQuery<RoleClaim> query = new EntityQuery<>(RoleClaim.class);
		query.eq(RoleClaim.FILED_ROLE_ID, roleId).orderBy(RoleClaim.FILED_ID);
		return query.selectByList(this.roleClaimRepository);
	}

	@Override
	public void addOrUpdateUserClaim(UserClaim claim) {
		ExceptionUtils.checkNotNull(claim, "claim");
		claim.forNullToDefault();
		claim.valid();
		EntityQuery<TUser> userQuery = new EntityQuery<>(this.getUserEntityClass());
		userQuery.eq(AbstractUser.FILED_ID, claim.getUserId());
		if (userQuery.countByWhere(this.getUserRepository()) == 0) {
			ExceptionUtils.throwValidationException("无效的用户或用户不存在。");
		}
		EntityQuery<UserClaim> claimQuery = new EntityQuery<>(UserClaim.class);
		claimQuery.eq(UserClaim.FILED_USER_ID, claim.getUserId()).eq(UserClaim.FILED_CLAIM_TYPE, claim.getClaimType());
		UserClaim oldClaim = claimQuery.selectByFirst(this.userClaimRepository);
		if (oldClaim == null) {
			this.userClaimRepository.insert(claim);
		} else {
			claim.setId(oldClaim.getId());

			oldClaim.setClaimValue(claim.getClaimValue());
			this.userClaimRepository.update(oldClaim);
		}
	}

	@Override
	public void deleteUserClaim(long userId, String claimType) {
		ExceptionUtils.checkNotNullOrBlank(claimType, "claimType");
		EntityQuery<UserClaim> claimQuery = new EntityQuery<>(UserClaim.class);
		claimQuery.eq(UserClaim.FILED_USER_ID, userId).eq(UserClaim.FILED_CLAIM_TYPE, claimType);
		claimQuery.deleteByWhere(this.userClaimRepository);
	}

	@Override
	public void addOrUpdateUserExternalProvider(UserExternalAuthLogin externalAuthLogin) {
		ExceptionUtils.checkNotNull(externalAuthLogin, "externalAuthLogin");
		externalAuthLogin.forNullToDefault();
		externalAuthLogin.valid();
		EntityQuery<TUser> userQuery = new EntityQuery<>(this.getUserEntityClass());
		userQuery.eq(AbstractUser.FILED_ID, externalAuthLogin.getUserId());
		if (userQuery.countByWhere(this.getUserRepository()) == 0) {
			ExceptionUtils.throwValidationException("无效的用户或用户不存在。");
		}
		EntityQuery<UserExternalAuthLogin> query = new EntityQuery<>(UserExternalAuthLogin.class);
		query.eq(UserExternalAuthLogin.FILED_USER_ID, externalAuthLogin.getUserId())
				.eq(UserExternalAuthLogin.FILED_PROVIDER, externalAuthLogin.getProvider());
		UserExternalAuthLogin old = query.selectByFirst(this.userExternalAuthLoginRepository);
		if (old == null) {
			this.userExternalAuthLoginRepository.insert(externalAuthLogin);
		} else {
			externalAuthLogin.setId(old.getId());
			old.setProviderKey(externalAuthLogin.getProviderKey());
			this.userExternalAuthLoginRepository.update(old);
		}
	}

	@Override
	public void deleteExternalUserProvider(long userId, String provider) {
		ExceptionUtils.checkNotNullOrBlank(provider, "provider");
		provider = provider.trim();
		EntityQuery<UserExternalAuthLogin> query = new EntityQuery<>(UserExternalAuthLogin.class);
		query.eq(UserExternalAuthLogin.FILED_USER_ID, userId).eq(UserExternalAuthLogin.FILED_PROVIDER, provider);
		query.deleteByWhere(this.userExternalAuthLoginRepository);
	}

	@Override
	public void addOrUpdateRoleClaim(RoleClaim claim) {
		ExceptionUtils.checkNotNull(claim, "claim");
		claim.forNullToDefault();
		claim.valid();
		EntityQuery<TRole> roleQuery = new EntityQuery<>(this.getRoleEntityClass());
		roleQuery.eq(AbstractRole.FILED_ID, claim.getRoleId());
		if (roleQuery.countByWhere(this.getRoleRepository()) == 0) {
			ExceptionUtils.throwValidationException("无效的角色或角色不存在。");
		}
		EntityQuery<RoleClaim> claimQuery = new EntityQuery<>(RoleClaim.class);
		claimQuery.eq(RoleClaim.FILED_ROLE_ID, claim.getRoleId()).eq(UserClaim.FILED_CLAIM_TYPE, claim.getClaimType());
		RoleClaim oldClaim = claimQuery.selectByFirst(this.roleClaimRepository);
		if (oldClaim == null) {
			this.roleClaimRepository.insert(claim);
		} else {
			claim.setId(oldClaim.getId());
			oldClaim.setClaimValue(claim.getClaimValue());
			this.roleClaimRepository.update(oldClaim);
		}
	}

	@Override
	public void deleteRoleClaim(long roleId, String claimType) {
		ExceptionUtils.checkNotNullOrBlank(claimType, "claimType");
		EntityQuery<RoleClaim> claimQuery = new EntityQuery<>(RoleClaim.class);
		claimQuery.eq(RoleClaim.FILED_ROLE_ID, roleId).eq(UserClaim.FILED_CLAIM_TYPE, claimType);
		claimQuery.deleteByWhere(this.roleClaimRepository);
	}

	@Override
	public void addUserLoginAttempt(UserLoginAttempt attempt) {
		ExceptionUtils.checkNotNull(attempt, "attempt");
		attempt.forNullToDefault();
		attempt.truncationString();
		attempt.valid();
		attempt.setGmtCreate(new Date());
		this.userLoginAttemptRepository.insert(attempt);
	}

	@Override
	public void addUserLoginLog(UserLoginLog userLoginLog) {
		ExceptionUtils.checkNotNull(userLoginLog, "userLoginLog");
		userLoginLog.forNullToDefault();
		userLoginLog.truncationString();
		userLoginLog.valid();
		userLoginLog.setGmtCreate(new Date());
		this.userLoginLogRepository.insert(userLoginLog);
	}

	/**
	 * 查找用户
	 * 
	 * @param filedName
	 * @param value
	 * @param isChild
	 * @return
	 */
	private TUser findUser(String filedName, String value, boolean isChild) {
		EntityQuery<TUser> query = new EntityQuery<>(this.getUserEntityClass());
		query.eq(filedName, value.trim()).lockByUpdate();
		TUser user = query.selectByFirst(this.getUserRepository());
		if (isChild && user != null) {
			user.setRoles(this.queryUserRoles(user.getId()));
		}
		return user;
	}

	@Override
	public TUser findUserByAccount(String account, boolean isChild) {
		ExceptionUtils.checkNotNullOrBlank(account, "account");
		account = account.trim();
		if (MatchesUtils.isMobilePhone(account)) {
			return this.findUser(AbstractUser.FILED_PHONE_NUMBER, account, isChild);
		} else if (MatchesUtils.isEmail(account)) {
			return this.findUser(AbstractUser.FILED_EMAIL_ADDRESS, account, isChild);
		} else {
			return this.findUser(AbstractUser.FILED_USER_NAME, account, isChild);
		}
	}

	@Override
	public TUser findUserByUserName(String userName, boolean isChild) {
		ExceptionUtils.checkNotNullOrBlank(userName, "userName");
		return this.findUser(AbstractUser.FILED_USER_NAME, userName, isChild);
	}

	@Override
	public TUser findUserByPhoneNumber(String phoneNumber, boolean isChild) {
		ExceptionUtils.checkNotNullOrBlank(phoneNumber, "phoneNumber");
		return this.findUser(AbstractUser.FILED_PHONE_NUMBER, phoneNumber, isChild);
	}

	@Override
	public TUser findUserByEmailAddress(String emailAddress, boolean isChild) {
		ExceptionUtils.checkNotNullOrBlank(emailAddress, "emailAddress");
		return this.findUser(AbstractUser.FILED_EMAIL_ADDRESS, emailAddress, isChild);
	}

	/**
	 * 判断用户是否存在
	 * 
	 * @param filedName
	 * @param value
	 * @return
	 */
	private boolean existUser(String filedName, String value) {
		EntityQuery<TUser> query = new EntityQuery<>(this.getUserEntityClass());
		query.eq(filedName, value.trim()).lockByUpdate();
		return query.exist(this.getUserRepository());
	}

	@Override
	public boolean existUserByAccount(String account) {
		ExceptionUtils.checkNotNullOrBlank(account, "account");
		account = account.trim();
		if (MatchesUtils.isMobilePhone(account)) {
			return this.existUser(AbstractUser.FILED_PHONE_NUMBER, account);
		} else if (MatchesUtils.isEmail(account)) {
			return this.existUser(AbstractUser.FILED_EMAIL_ADDRESS, account);
		} else {
			return this.existUser(AbstractUser.FILED_USER_NAME, account);
		}
	}

	@Override
	public boolean existUserByUserName(String userName) {
		ExceptionUtils.checkNotNullOrBlank(userName, "userName");
		return this.existUser(AbstractUser.FILED_USER_NAME, userName);
	}

	@Override
	public boolean existUserByPhoneNumber(String phoneNumber) {
		ExceptionUtils.checkNotNullOrBlank(phoneNumber, "phoneNumber");
		return this.existUser(AbstractUser.FILED_PHONE_NUMBER, phoneNumber);
	}

	@Override
	public boolean existUserByEmailAddress(String emailAddress) {
		ExceptionUtils.checkNotNullOrBlank(emailAddress, "emailAddress");
		return this.existUser(AbstractUser.FILED_EMAIL_ADDRESS, emailAddress);
	}

	private EntityQuery<UserExternalAuthLogin> createExternalProviderQuery(String provider, String providerKey) {
		ExceptionUtils.checkNotNullOrBlank(provider, "provider");
		ExceptionUtils.checkNotNullOrBlank(providerKey, "providerKey");
		provider = provider.trim();
		providerKey = providerKey.trim();
		EntityQuery<UserExternalAuthLogin> query = new EntityQuery<>(UserExternalAuthLogin.class);
		query.eq(UserExternalAuthLogin.FILED_PROVIDER, provider)
				.eq(UserExternalAuthLogin.FILED_PROVIDER_KEY, providerKey).lockByUpdate();
		return query;
	}

	@Override
	public TUser findUserByExternalProvider(String provider, String providerKey, boolean isChild) {
		EntityQuery<UserExternalAuthLogin> query = this.createExternalProviderQuery(provider, providerKey);
		UserExternalAuthLogin ueal = query.selectByFirst(this.userExternalAuthLoginRepository);
		if (ueal == null) {
			return null;
		}
		TUser user = this.getUserRepository().getByLock(ueal.getId(), LockModeEnum.UPDATE);
		if (isChild && user != null) {
			user.setRoles(this.queryUserRoles(user.getId()));
		}
		return user;
	}

	@Override
	public boolean existUserByExternalProvider(String provider, String providerKey) {
		EntityQuery<UserExternalAuthLogin> query = this.createExternalProviderQuery(provider, providerKey);
		return query.exist(this.userExternalAuthLoginRepository);
	}

}
